package com.prim.update.impl;

import android.content.Context;
import android.os.Environment;
import android.text.TextUtils;
import android.widget.Toast;

import com.prim.update.model.UpdateInfo;
import com.prim.update.UpdateManager;
import com.prim.update.interfaces.*;
import com.prim.update.listener.OnDownloadListener;
import com.prim.update.model.Progress;
import com.prim.update.notification.NotificationHelper;
import com.prim.update.state.StateType;
import com.prim.update.state.UpdateState;
import com.prim.update.utils.ApkUtils;
import com.prim.update.utils.FileUtils;
import com.prim.update.utils.SPUtils;
import com.prim.update.utils.Utils;

import java.io.File;
import java.lang.ref.WeakReference;

import static com.prim.update.impl.UpdateError.CHECK_NO_NETWORK;
import static com.prim.update.impl.UpdateError.CHECK_NO_WIFI;

/**
 * ================================================
 * 作    者：linksus
 * 版    本：1.0
 * 创建日期：3/5 0005
 * 描    述：版本更新的总管,分配和督查所有任务:
 * 以下为任务步骤
 * 任务开始 -- 总管得到管理者的决策后开始分配任务
 * 任务步骤1 - 检测版本更新            -->  具体实现者:{@link IUpdateChecker}
 * 任务步骤2 - 解析json转换为bean      -->  具体实现者:{@link IUpdateConverter}
 * 任务步骤3 - 对bean进行分析采取方案   -->  具体实现者:{@link IUpdatePlan}
 * 任务步骤4 - 版本更新UI提示          -->  具体实现者:{@link IUpdatePrompter}
 * 任务步骤5 - 下载apk                -->  具体实现者:{@link IUpdateDownloader}
 * 任务步骤6 - 下载过程中的UI显示      -->  具体实现者:{@link OnDownloadListener}
 * 任务步骤7 - 安装apk                -->  具体实现者:{@link IUpdateFile}
 * 任务步骤8 - 记录-过程穿插整个任务过程-->  具体实现者:{@link IUpdateLogger}
 * 任务完成 -- 由总管向管理者汇报任务情况,并把任务记录传给管理者
 * 中间可以插入扩展任务,具体实现看业务需求
 * 修订历史：
 * ================================================
 */
public class UpdateExplorer implements ICheckInfo, IUpdateExplorer, OnDownloadListener {
    private UpdateInfo updateInfo;
    private String info;
    private WeakReference<Context> mContext;
    private IUpdateChecker updateChecker;
    private IUpdateConverter updateConverter;
    private IUpdatePlan updatePlan;
    private IUpdatePrompter updatePrompter;
    private IUpdateDownloader updateDownloader;
    private IUpdateFile updateFile;
    private IUpdateLogger updateLogger;
    private OnDownloadListener downloadUIHandler;
    private OnDownloadListener downloadUINotificationHandler;
    private UpdateManager.Builder builder;
    private boolean cancleUpdate = false;

    public UpdateExplorer(WeakReference<Context> mContext, UpdateManager.Builder builder) {
        this.mContext = mContext;
        this.builder = builder;
        updateChecker = new UpdateChecker();
        updateConverter = new UpdateConverter();
        updatePlan = new UpdatePlaner();
        updatePrompter = new DefultUpdatePrompterUIHandler(mContext.get());
        updateDownloader = new UpdateDownloader(mContext.get());
        updateFile = new UpdateFiler(mContext.get());
        updateLogger = new UpdateLogger();
        downloadUIHandler = new DefaultDownloadUIHandler(mContext.get());
        downloadUINotificationHandler = new DefaultDownloadUINotificationHandler(mContext.get(), this, builder);
    }

    public enum PrompterType {
        update, install, download
    }

    @Override
    public UpdateManager.Builder getBuilder() {
        return builder;
    }

    @Override
    public void setInfo(String info) {
        this.info = info;
    }

    @Override
    public void setError(String msg) {
        showToast(msg);
    }

    @Override
    public UpdateInfo getInfo() {
        return updateInfo;
    }

    @Override
    public void setUpdateChecker(IUpdateChecker iUpdateChecker) {
        this.updateChecker = iUpdateChecker;
    }

    @Override
    public void setUpdateConverter(IUpdateConverter iUpdateConverter) {
        this.updateConverter = iUpdateConverter;
    }

    @Override
    public void setUpdatePlan(IUpdatePlan iUpdatePlan) {
        this.updatePlan = iUpdatePlan;
    }

    @Override
    public void setUpdatePrompter(IUpdatePrompter iUpdatePrompter) {
        this.updatePrompter = iUpdatePrompter;
    }

    @Override
    public void setUpdateDownloader(IUpdateDownloader iUpdateDownloader) {
        this.updateDownloader = iUpdateDownloader;
    }

    @Override
    public void setUpdateFile(IUpdateFile iUpdateFile) {
        this.updateFile = iUpdateFile;
    }

    @Override
    public void setUpdateLogger(IUpdateLogger iUpdateLogger) {
        this.updateLogger = iUpdateLogger;
    }

    @Override
    public void setDownloadUIHandler(OnDownloadListener downloadUIHandler) {
        this.downloadUIHandler = downloadUIHandler;
    }

    @Override
    public void setDownloadUINotificationHandler(OnDownloadListener downloadUINotificationHandler) {
        this.downloadUINotificationHandler = downloadUINotificationHandler;
    }

    @Override
    public void setCancleUpdate(boolean cancleUpdate) {
        this.cancleUpdate = cancleUpdate;
    }

    /** 是否允许静默下载 */
    @Override
    public boolean isBackstage() {
        return builder.isBackstage;
    }

    /** 是否在静默下载 */
    @Override
    public boolean isBackstageDownload() {
        return cancleUpdate && isBackstage();
    }

    @Override
    public void update() {
        if (cancleUpdate) {// 取消版本更新
            if (isBackstage()) {//允许静默下载
                if (!isApkCompleteExits()) {
                    doDownload();
                } else {
                    doPrompter(PrompterType.install);
                }
            } else { // 不允许静默下载
                stop();
            }
        } else {// 用户点击了更新 或者安装
            if (!isApkCompleteExits()) {
                doDownload();
            } else {
                doInstall();
            }
        }
    }

    /** 忽略该版本 不在进行提示 任务结束 */
    @Override
    public void ignore() {
        //记录用户忽略的版本
        SPUtils.getInstance("ignore").put(updateInfo.getVersion_name(), true);
        //终止任务
        stop();
    }

    /** 任务终止 进行清理操作 任务日志传递给管理者 任务完成 */
    @Override
    public void stop() {
        UpdateManager.getInstance().getHttpClient().cancleDownload();
        UpdateState.setState(StateType.STOP);
        cancleUpdate = false;
        doLogger();
    }

    /** 总管发布命令开始任务 */
    public void check() {
        /* 检查任务状态，是否在后台静默下载 */
        if (UpdateState.getState() == StateType.DOWNLOAD && cancleUpdate) {
            updatePrompter.prompt(this, PrompterType.update);
        } else {
            doCheck();
        }
    }

    private static final String TAG = "UpdateExplorer";

    /** 1 - 请求服务器,查询是否有更新 */
    @Override
    public void doCheck() {
        try {
            updateChecker.checker(this, this);
        } catch (Throwable throwable) {
            throwable.printStackTrace();
            stop();
        }
    }

    /** 2 - 解析json字符串 */
    @Override
    public void doConvert() {
        try {
            updateInfo = updateConverter.convertJson(info, this);//解析json字符串
            doPlan(updateInfo);
        } catch (Throwable throwable) {
            throwable.printStackTrace();
        }
    }

    /** 3 - 对bean采取方案,判断是否需要更新 */
    @Override
    public void doPlan(UpdateInfo updateInfo) {
        updatePlan.plan(updateInfo, this);
    }

    /** 4 - 更新UI提示 */
    @Override
    public void doPrompter(PrompterType type) {
        UpdateState.setState(StateType.PROMPTER);
        updatePrompter.prompt(this, type);
    }

    /** 5- 下载apk */
    @Override
    public void doDownload() {
        if (builder.isWifiOnly) {// 仅WiFi下下载文件
            if (Utils.checkWifi(mContext.get())) {
                updateDownloader.download(this, this, updateInfo.getDownloadUrl(), getDownloadPath());
            } else {
                setError(new UpdateError(CHECK_NO_WIFI).toString());
            }
        } else {
            if (Utils.checkNetwork(mContext.get())) {
                updateDownloader.download(this, this, updateInfo.getDownloadUrl(), getDownloadPath());
            } else {
                setError(new UpdateError(CHECK_NO_NETWORK).toString());
            }
        }
    }

    /** 6 - 安装apk */
    @Override
    public void doInstall() {
        NotificationHelper.getInstance().clearNotification();
        updateFile.checkFile(this);
        stop();
    }

    /** 7 - 任务日志 */
    @Override
    public void doLogger() {

    }

    @Override
    public boolean isAutoDownload() {
        return builder.isAutoDownload;
    }

    /** 是否显示UI提示 */
    @Override
    public boolean isShow() {
        return !cancleUpdate && !isAutoDownload();
    }

    // ------------------------------ 下载apk的监听回调 用于显示下载过程中的UI提示 ----------------------------- //
    @Override
    public void onStart() {
        if (builder.isNotificationShow) {
            downloadUINotificationHandler.onStart();
        }
        if (builder.isShowProgressDialog) {
            downloadUIHandler.onStart();
        }

        UpdateManager.getInstance().onStart();
    }

    @Override
    public void onProgress(Progress progress) {
        if (builder.isNotificationShow) {
            downloadUINotificationHandler.onProgress(progress);
        }
        if (builder.isShowProgressDialog) {
            downloadUIHandler.onProgress(progress);
        }

        UpdateManager.getInstance().onProgress(progress);
    }

    @Override
    public void onError(String msg) {
        if (builder.isNotificationShow) {
            downloadUINotificationHandler.onError(msg);
        }
        if (builder.isShowProgressDialog) {
            downloadUIHandler.onError(msg);
        }
        setError(msg);
        stop();

        UpdateManager.getInstance().onError(msg);
    }

    @Override
    public void onFinish() {
        if (builder.isNotificationShow) {
            downloadUINotificationHandler.onFinish();
        }
        if (builder.isShowProgressDialog) {
            downloadUIHandler.onFinish();
        }

        UpdateManager.getInstance().onFinish();
        //允许自动安装apk
        if (isAutoInstall()) {
            doInstall();
        } else {
            stop();
        }
    }

    /** 是否允许自动安装 */
    private boolean isAutoInstall() {
        return builder.isAutoInstall;
    }

    /** toast提示，注意要在UI线程中 */
    @Override
    public void showToast(final String msg) {
        UpdateManager.getInstance().runOnUiThread(new Runnable() {
            @Override
            public void run() {
                if (mContext != null)
                    Toast.makeText(mContext.get(), msg, Toast.LENGTH_LONG).show();
            }
        });
    }

    /** 获取文件下载目录(具体目录可根据具体的业务需求定制,修改此方法) */
    @Override
    public String getStoragePath() {
        if (!TextUtils.isEmpty(builder.storagePath)) {
            return Environment.getExternalStorageDirectory()
                    + File.separator
                    + builder.storagePath
                    + File.separator
                    + "Versions"
                    + File.separator;
        }
        return "";
    }

    /** 获取下载文件的名称(具体目录可根据具体的业务需求定制,修改此方法) */
    @Override
    public String getDownloadFileName() {
        if (!TextUtils.isEmpty(builder.storagePath) && !TextUtils.isEmpty(updateInfo.getVersion_code())) {
            return FileUtils.getDownloadFileName(updateInfo.getDownloadUrl(), updateInfo.getVersion_code());
        }
        return "";
    }

    /** 获取获取并下载路径 {@link #getStoragePath()} + {@link #getDownloadFileName()} */
    @Override
    public String getDownloadPath() {
        if (!TextUtils.isEmpty(builder.storagePath) && !TextUtils.isEmpty(updateInfo.getVersion_code())) {
            File file = new File(getStoragePath(), getDownloadFileName());
            return file.getAbsolutePath();
        }
        return "";
    }

    /** patch文件与oldApk合并后生成的新的apk的路径 */
    @Override
    public String getPatchNewApkPath() {
        if (!TextUtils.isEmpty(builder.storagePath) && !TextUtils.isEmpty(updateInfo.getVersion_code())) {
            File file = new File(getStoragePath(), FileUtils.getPatchDownloadFileName(updateInfo.getDownloadUrl(), updateInfo.getVersion_code()));
            return file.getAbsolutePath();
        }
        return "";
    }

    public void cancelPrompterTime() {
        SPUtils.getInstance("Update").clear();
    }

    public void cancelIgnorable() {
        SPUtils.getInstance("ignore").clear();
    }

    @Override
    public boolean deleteApkFile() {
        return FileUtils.deleteFile(getDownloadPath());
    }

    /** 判断是否已经下载最新的并且完整的apk包 */
    @Override
    public boolean isApkCompleteExits() {
        File file = new File(getStoragePath(), getDownloadFileName());
        return file.exists() && ApkUtils.getUninatllApkInfo(mContext.get(), file.getAbsolutePath());
    }

    @Override
    public boolean isApkExits() {
        File file = new File(getStoragePath(), getDownloadFileName());
        return file.exists();
    }

}
